﻿using System;
using System.IO;
using Freesql.Tool.Helpers;
using Freesql.Tool.Models;
using System.Collections.Generic;
using RazorEngineCore;
using SkiaSharp;
using Aspose.Cells;
using System.Xml.Linq;

namespace Freesql.Tool
{
    class MainClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("按回车键生成指定Entity代码，其他键生成全局代码");
            var mode = Console.ReadKey();
            if (mode.Key == ConsoleKey.Enter)
            {
                var config = Environment.OSVersion.Platform == PlatformID.Win32NT ? "Config.Win.txt" : "Config.txt";
                if (QuickStart(config))
                {
                    Console.WriteLine("恭喜成功生成代码，按任意键结束!");
                }
            }
            else
            {
                if (QuickStart())
                {
                    Console.WriteLine("恭喜成功生成代码，按任意键结束!");
                }
            }
            Console.ReadKey();

        }
        #region all
        private static bool QuickStart()
        {
            var path = Environment.OSVersion.Platform == PlatformID.Win32NT ? "All.Win.txt" : "All.txt";
            var lines = File.ReadAllLines(path);
            var rootPath = Directory.GetParent(path)!.FullName;
            var urls = new List<string>();
            var model = new RazorAllTemplateModel();
            var resultPath = string.Empty;
            foreach (var item in lines)
            {
                if (string.IsNullOrEmpty(item) || item.StartsWith(";"))
                {
                    continue;
                }
                else if (item.StartsWith("-Prefix "))
                {
                    model.Prefix = item.Replace("-Prefix ", "").Trim();
                }
                else if (item.StartsWith("-Swagger "))
                {
                    urls.Add(item.Replace("-Swagger ", "").Trim());
                }
                else if (item.StartsWith("-Out "))
                {
                    resultPath = item.Replace("-Out ", "").Trim();
                }

                if (item.StartsWith("-Apis"))
                {
                    var tPath = item.Replace("-Apis ", "").Trim();
                    var list = new List<Api>();
                    foreach (var url in urls)
                    {
                        list.AddRange(ReflectionHelper.GetApiFromSwagger(url));
                    }
                    var files = list.Select(p => p.File).Distinct();
                    foreach (var file in files)
                    {
                        var apis = list.Where(p => p.File == file).ToList();
                        model.Apis = apis;
                        var paths = tPath.Replace("{class}", file).Split(',');
                        paths[1] = Path.Combine(resultPath, paths[1]);
                        var inPath = IsAbsolute(paths[0]) ? paths[0] : Path.Combine(rootPath, paths[0]);
                        var outPath = IsAbsolute(paths[1]) ? paths[1] : Path.Combine(rootPath, paths[1]);
                        OutTemplate(inPath, outPath, model);
                    }
                }
                else if (item.StartsWith("-Inputs "))
                {
                    var types = typeof(LF.Shared.Dtos.Input.FileInput).Assembly.GetTypes();
                    foreach (var type in types)
                    {
                        if (type.Namespace != null && type.Namespace.StartsWith(typeof(LF.Shared.Dtos.Input.FileInput).Namespace!))
                        {
                            var tPath = item.Replace("-Inputs ", "").Trim();
                            OutApi(rootPath, resultPath, tPath, type, false);
                        }
                    }
                }
                else if (item.StartsWith("-Outs "))
                {
                    var types = typeof(LF.Shared.Dtos.Out.AppDicOut).Assembly.GetTypes();
                    foreach (var type in types)
                    {
                        if (type == typeof(LF.Shared.Dtos.Out.Result)
                            || type == typeof(LF.Shared.Dtos.Out.Result<>)
                            || type == typeof(LF.Shared.Dtos.Out.BaseSearchOut<>))
                            continue;
                        if (type.Namespace != null && type.Namespace.StartsWith(typeof(LF.Shared.Dtos.Out.AppDicOut).Namespace!))
                        {
                            var tPath = item.Replace("-Outs ", "").Trim();
                            OutApi(rootPath, resultPath, tPath, type, false);
                        }
                    }
                }
                else if (item.StartsWith("-Enums "))
                {
                    var tPath = item.Replace("-Enums ", "").Trim();
                    OutApi(rootPath, resultPath, tPath, typeof(object));
                }
            }
            return true;
        }

        private static void OutApi(string rootPath, string oPath, string tPath, Type type, bool lower = true)
        {
            var name = lower ? ReflectionHelper.ToLowerFirst(type.Name) : type.Name;
            if (name.EndsWith("Service"))
            {
                name = name.Replace("Service", "");
            }
            tPath = tPath.Replace("{class}", name);
            var paths = tPath.Split(',');
            paths[1] = Path.Combine(oPath, paths[1]);
            var inPath = IsAbsolute(paths[0]) ? paths[0] : Path.Combine(rootPath, paths[0]);
            var outPath = IsAbsolute(paths[1]) ? paths[1] : Path.Combine(rootPath, paths[1]);
            OutTemplate(inPath, outPath, new RazorAllTemplateModel { Type = type });
        }
        #endregion

        #region table
        private static bool QuickStart(string path)
        {
            if (!File.Exists(path))
            {
                Console.WriteLine($"配置文件 {path} 不存在!");
                return false;
            }
            var rootPath = Directory.GetParent(path)!.FullName;
            var lines = File.ReadAllLines(path);
            var model = new RazorTemplateModel
            {
                UserInfo = new CopyRightUserInfo
                {
                    CreateTime = DateTime.Now
                }
            };
            var tables = "";
            var templates = new List<string>();
            foreach (var item in lines)
            {
                if (string.IsNullOrEmpty(item) || item.StartsWith(";"))
                {
                    continue;
                }
                if (item.StartsWith("-Author"))
                {
                    model.UserInfo.Author = item.Replace("-Author", "").Trim();
                }
                else if (item.StartsWith("-Email"))
                {
                    model.UserInfo.Email = item.Replace("-Email", "").Trim();
                }
                else if (item.StartsWith("-NameSpace"))
                {
                    model.NameSpace = item.Replace("-NameSpace", "").Trim();
                }
                else if (item.StartsWith("-Manager"))
                {
                    model.Manager = item.Replace("-Manager", "").Trim();
                }
                else if (item.StartsWith("-Service"))
                {
                    model.Service = item.Replace("-Service", "").Trim();
                }
                else if (item.StartsWith("-Vue"))
                {
                    model.Vue = item.Replace("-Vue", "").Trim();
                }
                else if (item.StartsWith("-TableNames"))
                {
                    tables = item.Replace("-TableNames", "").Trim();
                }
                else if (item.StartsWith("-Out"))
                {
                    model.OutPath = item.Replace("-Out", "").Trim();
                }
                else if (item.StartsWith("-T"))
                {
                    var template = item.Replace("-T", "").Trim();
                    if (!string.IsNullOrEmpty(template))
                    {
                        templates.Add(template);
                    }
                }
            }
            if (string.IsNullOrEmpty(tables) || templates.Count == 0)
            {
                Console.WriteLine("无需处理!");
                return false;
            }

            var str = "";
            foreach (var item in tables.Split(','))
            {
                str += $"""
                    CreateMap<E.{item}, O.{item}Out>()
                      .IgnoreAllNonExisting();
                    CreateMap<O.{item}Out,E.{item}>()
                    .IgnoreAllNonExisting();

                    """;
                Console.WriteLine($"======{item}======");
                foreach (var template in templates)
                {
                    model.TableName = item.ToFirstUp();
                    if (string.IsNullOrEmpty(model.Manager))
                    {
                        model.Manager = model.TableName;
                    }
                    if (model.Manager != item && template.EndsWith("Service.cs"))
                    {
                        continue;
                    }
                    var tPath = template
                        .Replace("{NameSpace}", model.NameSpace)
                        .Replace("{TableName}", model.TableName)
                        .Replace("{LowerTableName}", model.LowerTableName)
                        .Replace("{Vue}", model.Vue);
                    var paths = tPath.Split(',');
                    if (paths.Length > 1)
                    {
                        model.UserInfo.CreateTime = DateTime.Now;
                        paths[1] = Path.Combine(model.OutPath, paths[1]);
                        var inPath = IsAbsolute(paths[0]) ? paths[0] : Path.Combine(rootPath, paths[0]);
                        var outPath = IsAbsolute(paths[1]) ? paths[1] : Path.Combine(rootPath, paths[1]);
                        OutTemplate(inPath, outPath, model);
                    }
                }
            }
            File.WriteAllText(Path.Combine(model.OutPath, "SijiProfile.txt"), str);
            return true;
        }

        /// <summary>
        /// 是否绝对路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private static bool IsAbsolute(string path)
        {
            return path.StartsWith('/') || path.Length > 1 && path.Substring(1, 1) == ":";
        }
        /// <summary>
        /// 模板输出对应文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="outPath"></param>
        /// <param name="model"></param>
        private static void OutTemplate(string path, string outPath, object model)
        {
            var templateStr = File.ReadAllText(path);
            IRazorEngine razorEngine = new RazorEngine();
            IRazorEngineCompiledTemplate template = razorEngine.Compile(templateStr, builder =>
            {
                builder.AddAssemblyReference(typeof(Helpers.TextHelper));
                builder.AddAssemblyReferenceByName("System.Collections");
            });
            var result = template.Run(model);
            var dir = Path.GetDirectoryName(outPath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir!);
            }
            File.WriteAllText(outPath, result);
            Console.WriteLine($"{outPath} done!");
        }
        #endregion

    }
}
